package com.leinao.media.callback;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.leinao.media.entity.MediaThermalCameraAlarm;
import com.leinao.media.exception.MediaException;
import com.leinao.media.mapper.MediaThermalCameraAlarmMapper;
import com.leinao.media.sdk.hk.HCNetSDK;
import com.sun.jna.Pointer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 红外相机报警信息回调函数
 *
 * @author zhangyu
 */
@Component
public class FMSGCallBack implements HCNetSDK.FMSGCallBack_V31 {

    private static final Log log = LogFactory.get();

    @Value("${file.saveAddress}")
    private String alarmPath;

    @Value("${ip_port}")
    private String ipAndPort;

    @Autowired
    private MediaThermalCameraAlarmMapper alarmMapper;

    @Override
    public boolean invoke(int lCommand, HCNetSDK.NET_DVR_ALARMER pAlarmer, Pointer pAlarmInfo, int dwBufLen, Pointer pUser) {
        List<String[]> reList = alarmDataHandle(lCommand, pAlarmer, pAlarmInfo, dwBufLen, pUser);
        for (String[] strings : reList) {
            for (int j = 0; j < 3; j++) {
                log.info(strings[j]);
            }
        }
        return true;
    }

    /**
     * 报警信息回调函数实现
     *
     * @param lCommand   上传的消息类型，不同的报警信息对应不同的类型，通过类型区分是什么报警信息
     * @param pAlarmer   报警设备信息，包括设备序列号、IP地址、登录IUserID句柄等
     * @param pAlarmInfo 报警信息，通过lCommand值判断pAlarmer对应的结构体
     * @param dwBufLen   报警信息缓存大小
     * @param pUser      用户数据
     * @return 报警信息集合
     */
    public List<String[]> alarmDataHandle(int lCommand, HCNetSDK.NET_DVR_ALARMER pAlarmer, Pointer pAlarmInfo,
                                          int dwBufLen, Pointer pUser) {

        log.info("lCommand = 0x,{}", Integer.toHexString(lCommand));
        // alarmList 为报警信息集合
        List<String[]> alarmList = new ArrayList<>();
        String[] newRow = new String[3];

        // 报警时间
        Date today = new Date();
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        String[] sIP;

        String sAlarmType = "lCommand = 0x" + Integer.toHexString(lCommand);

        // lCommand是传的报警类型
        // 温度报警
        if (lCommand == HCNetSDK.COMM_THERMOMETRY_ALARM) {
            HCNetSDK.NET_DVR_THERMOMETRY_ALARM alarm = new HCNetSDK.NET_DVR_THERMOMETRY_ALARM();
            alarm.write();
            Pointer pThermAlarm = alarm.getPointer();
            pThermAlarm.write(0, pAlarmInfo.getByteArray(0, alarm.size()), 0, alarm.size());
            alarm.read();

            String strRegion = ", 区域坐标:";
            for (int i = 0; i < alarm.struRegion.dwPointNum; i++) {
                strRegion = strRegion + "[" + alarm.struRegion.struPos[i].fX + "," +
                        alarm.struRegion.struPos[i].fY + "]";
            }
            sAlarmType = sAlarmType + "：温度报警信息, 通道号:" + alarm.dwChannel +
                    ", 规则标定类型:" + alarm.byRuleCalibType +
                    ", 规则ID:" + alarm.byRuleID +
                    ", 报警类型:" + alarm.byAlarmType +
                    ", 报警规则:" + alarm.byAlarmRule +
                    ", 报警温度:" + alarm.fRuleTemperature +
                    ", 当前温度:" + alarm.fCurrTemperature +
                    strRegion;

            log.info(sAlarmType);

            newRow[0] = dateFormat.format(today);
            // 报警类型
            newRow[1] = sAlarmType;
            // 报警设备IP地址
            sIP = new String(pAlarmer.sDeviceIP).split("\0", 2);
            newRow[2] = sIP[0];

            // 如果报警文件夹不存在，则创建文件夹
            String path = alarmPath + "alarm" + File.separator + DateUtil.format(new Date(), "yyyy-MM-dd") + File.separator;
            FileUtil.mkdir(new File(path));

            // 保存热成像图片
            String filename = "";
            if ((alarm.dwThermalPicLen > 0) && (alarm.pThermalPicBuff != null)) {
                SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmss");
                String newName = sf.format(new Date());
                FileOutputStream fout;
                try {
                    filename = path + new String(pAlarmer.sDeviceIP).trim() + "_" + newName + "_alarm.jpg";
                    fout = new FileOutputStream(filename);
                    //将字节写入文件
                    long offset = 0;
                    ByteBuffer buffers = alarm.pThermalPicBuff.getByteBuffer(offset, alarm.dwThermalPicLen);
                    byte[] bytes = new byte[alarm.dwThermalPicLen];
                    buffers.rewind();
                    buffers.get(bytes);
                    fout.write(bytes);
                    fout.close();
                } catch (IOException e) {
                    log.error("保存温度异常报警热成像图片出现错误：{}", e);
                    throw new MediaException("保存温度异常报警热成像图片出现错误");
                }
            }

            // 报警数据入库
            MediaThermalCameraAlarm cameraAlarm = new MediaThermalCameraAlarm();
            // ip转换
            String[] strings = new String(pAlarmer.sDeviceIP).split("\0");
            StringBuilder ip = new StringBuilder();
            for (String s : strings) {
                ip.append(s);
            }
            cameraAlarm.setIp(ip.toString());
            cameraAlarm.setPort(String.valueOf(pAlarmer.wLinkPort));
            cameraAlarm.setChannel(alarm.dwChannel);
            cameraAlarm.setPresetPoint((int) alarm.wPresetNo);
            cameraAlarm.setRuleId((int) alarm.byRuleID);
            cameraAlarm.setThermometryUnit((int) alarm.byThermometryUnit);
            cameraAlarm.setAlarmLevel((int) alarm.byAlarmLevel);
            cameraAlarm.setAlarmType((int) alarm.byAlarmType);
            cameraAlarm.setAlarmRule((int) alarm.byAlarmRule);
            cameraAlarm.setRuleCalibType((int) alarm.byRuleCalibType);
            cameraAlarm.setRuleTemperature(alarm.fRuleTemperature);
            cameraAlarm.setCurrTemperature(alarm.fCurrTemperature);
            cameraAlarm.setPicUrl(ipAndPort + filename);

            alarmMapper.insert(cameraAlarm);
        } else {
            newRow[0] = dateFormat.format(today);
            // 报警类型
            newRow[1] = sAlarmType;
            // 报警设备IP地址
            sIP = new String(pAlarmer.sDeviceIP).split("\0", 2);
            newRow[2] = sIP[0];
            alarmList.add(newRow);
        }
        return alarmList;
    }
}
